/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package thread;

import algorithm.BlobAlgorithm;
import algorithm.SkinDetectionAlgorithm;
import algorithm.ThreadAlgorithmCount;
import drivers.WebcamUSB;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.beans.PropertyVetoException;
import java.util.logging.Level;
import java.util.logging.Logger;
import recognize.RecognizeObjectsOpenCV;
import transferObject.ToAlgorithmHAARTO;
import transferObject.BlackWhiteImageTO;
import transferObject.CamImageTO;
import transferObject.ProcessingImageTO;
import structure.StructureBlob;
import algorithm.AlgorithmImgDiff;
import algorithm.BlobFinder;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import test.Erosion;
import transferObject.BlackWhiteImageToBlobTO;
import transferObject.ToAlgorithmSkinTO;
import util.Normalization;
import util.Utils;
import view.ViewCameraPanel;

/**
 *
 * @author Progresywny Maciek
 */
public class InstanceThreadUSB extends ViewCameraPanel implements ViewPanelInterface {

    private WebcamUSB webcam;
    private CamImageTO camImage;
    private BlackWhiteImageTO blackWhiteImage;
    private ProcessingImageTO processingImage;
    //private RecognizeObjectJJIL recognizeObject;
    private RecognizeObjectsOpenCV recognizeObjectCVFront;
    private RecognizeObjectsOpenCV recognizeObjectCVProfil;
    private BlobAlgorithm blobAlgorithm;
    private StructureBlob structBlobs;
    private SkinDetectionAlgorithm skinDetectionAlgorithm;
    private ToAlgorithmSkinTO toAlgorithmSkin;
    private BlackWhiteImageToBlobTO blackWhiteImageToBlob;
    private int binaryParameter=50;
    private int view = 0;
    //private RecognizeObjectsViolaJones recognizeObjectVJ;
    public static int frequence = 25;
    private int brightness = 0;
    private int squareSize = 20;
    private int speedMove = 5;
    private int contrast = 0;
    private int median = 1;
    private int minMass = 0;
    private long detectStartTime = 0;
    private Rectangle[] r;
    private boolean medianFilter = false;
    private boolean algFrontFace = true;
    private boolean algProfilFace = false;
    private boolean algSkinFace = false;
    private boolean equalizeHistogram = false;
    private boolean algDiff=false;
    private AlgorithmImgDiff algoruthmImgDiff;
    private LinkedList<ProcessingImageTO> fifoProcessingImage;
    //private int threadAlgorithmCount=0;
    private ThreadAlgorithmCount thdCount;
    private BufferedImage previousFrame;

    public InstanceThreadUSB(int cameraID) {
        this.frequence = 25;
        this.webcam = new WebcamUSB(cameraID);
        //this.recognizeObject = new RecognizeObjectJJIL();
        this.recognizeObjectCVFront = new RecognizeObjectsOpenCV();
        this.recognizeObjectCVProfil = new RecognizeObjectsOpenCV();
        //this.recognizeObjectVJ = new RecognizeObjectsViolaJones();
        this.camImage = new CamImageTO();
        this.processingImage = new ProcessingImageTO();
        this.blackWhiteImage = new BlackWhiteImageTO();
        this.blobAlgorithm = new BlobAlgorithm();
        this.structBlobs = new StructureBlob();
        //this.toAlgorithmHAAR = new ToAlgorithmHAARTO();
        this.toAlgorithmSkin = new ToAlgorithmSkinTO();
        this.skinDetectionAlgorithm = new SkinDetectionAlgorithm();
        this.blackWhiteImageToBlob = new BlackWhiteImageToBlobTO();
        this.thdCount = new ThreadAlgorithmCount();
        this.algoruthmImgDiff = new AlgorithmImgDiff();
        this.fifoProcessingImage = new LinkedList<>();
        
        initInterface();
        t.start();
        Point p1=new Point(85,0);
        Point p2=new Point(85,144);
        thdCount.setP1(p1);
        thdCount.setP2(p2);
        thdCount.setStructure(structBlobs);
        thdCount.start();
    }

    private void initInterface() {
        
        alg_bin.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                alg_binStateChanged(evt);
            }
        });
        
        flow_positionLine.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                flow_positionLineActionPerformed(evt);
            }
        }); 
          flow_positionLine1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                flow_positionLine1ActionPerformed(evt);
            }
        }); 
        alg_noiser.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                alg_noiserActionPerformed(evt);
            }
        });

        close.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeActionPerformed(evt);
            }
        });

        start.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startActionPerformed(evt);
            }
        });

        alg_loadFront.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                alg_loadFrontActionPerformed(evt);
            }
        });

        alg_loadProfil.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                alg_loadProfilActionPerformed(evt);
            }
        });

        stop.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopActionPerformed(evt);
            }
        });

        par_brightness.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                par_brightnessStateChanged(evt);
            }
        });

        par_contrast.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                par_contrastStateChanged(evt);
            }
        });

        alt_frequence.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                alt_frequenceStateChanged(evt);
            }
        });

        alg_binar.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                alg_binarStateChanged(evt);
            }
        });

        flo_leftSide.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                flo_leftSide(evt);
            }
        });

        flo_rightSide.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                flo_rightSide(evt);
            }
        });

        alg_frontFace.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                alg_frontFaceActionPerformed(evt);
            }
        });
        
          alg_diff.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                alg_diffActionPerformed(evt);
            }
        });
        
        par_equalizeHistogram.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                par_equalizeHistogramActionPerformed(evt);
            }
        });

        alg_profilFace.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                alg_profilFaceActionPerformed(evt);
            }
        });

        alg_skinFace.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                alg_skinFaceActionPerformed(evt);
            }
        });

        changeResolution.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                changeResolutionPerformed(evt);
            }
        });

        view1.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                viewStateChanged(evt);
            }
        });
        view2.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                viewStateChanged(evt);
            }
        });
        view3.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                viewStateChanged(evt);
            }
        });
        view4.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                viewStateChanged(evt);
            }
        });
        view5.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                viewStateChanged(evt);
            }
        });

        view6.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                viewStateChanged(evt);
            }
        });

        Dimension d = this.webcam.getSize();
        alg_width.setText(Integer.toString(d.width));
        alg_height.setText(Integer.toString(d.height));
        alg_noise.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                alg_noiseActionPerformed(evt);
            }
        });
    }

    public void closeActionPerformed(java.awt.event.ActionEvent evt) {
        try {
            webcam.closeCamera();
            t.interrupt();
            setClosed(true);
        } catch (PropertyVetoException ex) {
            Logger.getLogger(InstanceThreadUSB.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void alg_loadFrontActionPerformed(java.awt.event.ActionEvent evt) {
        t.suspend();
        this.recognizeObjectCVFront = new RecognizeObjectsOpenCV(alg_cascadeFront.getSelectedItem().toString());
        t.resume();
    }

    public void alg_loadProfilActionPerformed(java.awt.event.ActionEvent evt) {
        t.suspend();
        this.recognizeObjectCVProfil = new RecognizeObjectsOpenCV(alg_cascadeProfil.getSelectedItem().toString());
        t.resume();
    }

    public void startActionPerformed(java.awt.event.ActionEvent evt) {
        t.resume();
    }
    
    public void flow_positionLineActionPerformed(java.awt.event.ActionEvent evt) {
       
                System.out.println(mCH.getX()+" "+mCH.getY());
                thdCount.setP1(new Point(mCH.getX(), mCH.getY()));     
    }

    public void flow_positionLine1ActionPerformed(java.awt.event.ActionEvent evt) { 
        System.out.println(mCH.getX()+" "+mCH.getY());
                thdCount.setP2(new Point(mCH.getX(), mCH.getY()));    
    }

    public void alg_noiserActionPerformed(java.awt.event.ActionEvent evt) {
        median = Integer.parseInt(alg_noiser.getSelectedItem().toString());
        System.out.println(median);
    }

    public void stopActionPerformed(java.awt.event.ActionEvent evt) {
        t.suspend();
    }

    public void par_brightnessStateChanged(javax.swing.event.ChangeEvent evt) {
        brightness = par_brightness.getValue();
    }

    public void par_contrastStateChanged(javax.swing.event.ChangeEvent evt) {
        contrast = par_contrast.getValue();
    }

    public void alt_frequenceStateChanged(javax.swing.event.ChangeEvent evt) {
        frequence = alt_frequence.getValue();
        alg_fps.setText(alt_frequence.getValue() + " fps");
    }

    public void alg_binarStateChanged(javax.swing.event.ChangeEvent evt) {
        minMass = alg_binar.getValue();
        alg_minMass.setText(Integer.toString(alg_binar.getValue()));
    }

    public void flo_leftSide(javax.swing.event.ChangeEvent evt) {
        flow_width_square.setText(Integer.toString(flo_leftSide.getValue()));
    }

    public void flo_rightSide(javax.swing.event.ChangeEvent evt) {
        flow_speedMove.setText(Integer.toString(flo_rightSide.getValue()));
    }

    public void alg_frontFaceActionPerformed(java.awt.event.ActionEvent evt) {
        if (algFrontFace == false) {
            algFrontFace = true;
        } else {
            algFrontFace = false;
        }
    } 
    
       public void alg_diffActionPerformed(java.awt.event.ActionEvent evt) {
        if (algDiff == false) {
            algDiff = true;
        } else {
            algDiff = false;
        }
    } 

   public void par_equalizeHistogramActionPerformed(java.awt.event.ActionEvent evt) {
        if (equalizeHistogram == false) {
           equalizeHistogram=true;
        } else {
            equalizeHistogram=false;
        }
    }
            
    public void alg_profilFaceActionPerformed(java.awt.event.ActionEvent evt) {
        if (algProfilFace == false) {
            algProfilFace = true;
        } else {
            algProfilFace = false;
        }
    }

    public void alg_skinFaceActionPerformed(java.awt.event.ActionEvent evt) {
        if (algSkinFace == false) {
            algSkinFace = true;
        } else {
            algSkinFace = false;
        }
    }

    public void changeResolutionPerformed(java.awt.event.ActionEvent evt) {
        if ((alg_width.getValue() == 176 || alg_width.getValue() == 320 || alg_width.getValue() == 640) && (alg_height.getValue() == 144 || alg_height.getValue() == 240 || alg_height.getValue() == 480)) {
            t.suspend();
            webcam.closeCamera();
            webcam.setSize(Integer.parseInt(alg_width.getValue().toString()), Integer.parseInt(alg_height.getValue().toString()));
            webcam.openCamera();
            t.resume();
        } else {
        }
    }
    
     private void alg_binStateChanged(javax.swing.event.ChangeEvent evt) {                                     
      binaryParameter=Integer.decode(alg_bin.getValue().toString());
    }    

    public void alg_noiseActionPerformed(java.awt.event.ActionEvent evt) {
        if (medianFilter == false) {
            medianFilter = true;
        } else {
            medianFilter = false;
        }
    }

    private void viewStateChanged(javax.swing.event.ChangeEvent evt) {
        if (view1.isSelected() == true) {
            view = 0;
        }
        if (view2.isSelected() == true) {
            view = 1;
        }
        if (view3.isSelected() == true) {
            view = 2;
        }
        if (view4.isSelected() == true) {
            view = 3;
        }
        if (view5.isSelected() == true) {
            view = 4;
        }
        if (view6.isSelected() == true) {
            view = 5;
        }
    }
    
    public Thread t = new Thread(new Runnable() {
       
        public synchronized void run() {
           
            while (true) {
                try {
                    detectStartTime = System.currentTimeMillis();
                    camImage.setFrame(webcam.getOneFrame().getFrame());
                    if (view == 0) {

                        p.setImage(camImage.getFrame());
                        p.repaintImage();
                    }

                    processingImage.setFrame(camImage.getFrame());
                    processingImage.preprocessing(brightness, contrast, equalizeHistogram);

                    if (view == 1) {
                        p.setImage(processingImage.getFrame());
                        p.repaintImage();
                    }

                    //1 Detekcja HAAR tylko
                    if ((algFrontFace == true || algProfilFace == true) && algSkinFace == false) {
                        if (algFrontFace == true && algProfilFace == false) {
                            r = recognizeObjectCVFront.recognize(processingImage.getFrame());
                            blackWhiteImage.getBlackWhite(r, processingImage.getWidth(), processingImage.getHeight());
                            structBlobs = blobAlgorithm.getBlobs(blackWhiteImage.getFrame());  
                        }
                        if (algProfilFace == true && algFrontFace == false) {
                            r = recognizeObjectCVProfil.recognize(processingImage.getFrame());
                            blackWhiteImage.getBlackWhite(r, processingImage.getWidth(), processingImage.getHeight());
                            structBlobs = blobAlgorithm.getBlobs(blackWhiteImage.getFrame());    
                        }
                        if (algFrontFace == true && algProfilFace == true) {
                            r = recognizeObjectCVFront.recognize(processingImage.getFrame());
                            if (r == null) {
                                r = recognizeObjectCVProfil.recognize(processingImage.getFrame());
                            }
                            blackWhiteImage.getBlackWhite(r, processingImage.getWidth(), processingImage.getHeight());
                            structBlobs = blobAlgorithm.getBlobs(blackWhiteImage.getFrame());     
                        }
                    } else {
                        r = null;
                    }

                    //2 Detekcja Skin tylko
                    if (algSkinFace == true && algFrontFace == false && algProfilFace == false) {
                        if (medianFilter == true) {
                           
                            toAlgorithmSkin.setFrame(skinDetectionAlgorithm.detect(processingImage.getFrame()));
                             Erosion e=new Erosion(Utils.getSkinToBlackWhite(toAlgorithmSkin.getFrame()));
                             e.setNumberOfNeighbours(median);
                             e.runErosion();
                             blackWhiteImageToBlob.setFrame(e.getErosionResult());
                        } else {
                            toAlgorithmSkin.setFrame(skinDetectionAlgorithm.detect(processingImage.getFrame()));
                            blackWhiteImageToBlob.setFrame(Utils.getSkinToBlackWhite(toAlgorithmSkin.getFrame()));
                        }
                      
                        blobAlgorithm.setMinMass(minMass);
                        structBlobs = blobAlgorithm.getBlobs(blackWhiteImageToBlob.getFrame());
                    }

                    //3 Mix detekcja Skin i Haar
                    if ((algFrontFace == true || algProfilFace == true) && algSkinFace == true) {
                        if (algFrontFace == true && algProfilFace == false) {
                            r = recognizeObjectCVFront.recognize(processingImage.getFrame());
                        }
                        if (algProfilFace == true && algFrontFace == false) {
                            r = recognizeObjectCVProfil.recognize(processingImage.getFrame());
                        }
                        if (algFrontFace == true && algProfilFace == true) {
                            r = recognizeObjectCVFront.recognize(processingImage.getFrame());
                            if (r == null) {
                                r = recognizeObjectCVProfil.recognize(processingImage.getFrame());
                            }
                        }
                        if (medianFilter == true) {
                            toAlgorithmSkin.setFrame(skinDetectionAlgorithm.detect(processingImage.getFrame()));
                            blackWhiteImage.getBlackWhite(r, processingImage.getWidth(), processingImage.getHeight());
                            blackWhiteImageToBlob.setFrame(Utils.getImageAndImage(blackWhiteImage.getFrame(), Utils.getMedianSkinToBlackWhite(Utils.getSkinToBlackWhite(toAlgorithmSkin.getFrame()))));
                            structBlobs = blobAlgorithm.getBlobs(blackWhiteImageToBlob.getFrame());
                        } else {
                            toAlgorithmSkin.setFrame(skinDetectionAlgorithm.detect(processingImage.getFrame()));
                            blackWhiteImage.getBlackWhite(r, processingImage.getWidth(), processingImage.getHeight());
                            blackWhiteImageToBlob.setFrame(Utils.getImageAndImage(blackWhiteImage.getFrame(), Utils.getSkinToBlackWhite(toAlgorithmSkin.getFrame())));
                            structBlobs = blobAlgorithm.getBlobs(blackWhiteImageToBlob.getFrame());
                        }
                    }
                    
                    if (algDiff == true && algFrontFace == false && algProfilFace == false && algSkinFace == false) {
                            if(previousFrame!=null){
                            blackWhiteImageToBlob.setFrame(Normalization.binaringImage(Normalization.RGBnagrayscale(algoruthmImgDiff.proces( previousFrame, processingImage.getFrame()),BufferedImage.TYPE_BYTE_GRAY),(byte)binaryParameter));
                            blobAlgorithm.setMinMass(minMass);
                            structBlobs = blobAlgorithm.getBlobs(blackWhiteImageToBlob.getFrame());
                            }
                            previousFrame=Utils.deepCopy(processingImage.getFrame());
                            
                    }

                    if (view == 2) {
                        if (algFrontFace == false && algProfilFace == false && algSkinFace == true) {
                            p.setImage(toAlgorithmSkin.getFrame());
                        }
                        if ((algFrontFace == true || algProfilFace == true) && algSkinFace == false) {
                            p.setImage(processingImage.getFrame());
                            p.setRectagles(r);
                        }
                        p.repaintImage();
                    }


                    if (view == 3) {
                        if ((algFrontFace == true || algProfilFace == true) && algSkinFace == true ) {
                            p.setImage(blackWhiteImageToBlob.getFrame());
                        } 
                        if ((algFrontFace == true || algProfilFace == true) && algSkinFace == false) {
                            p.setImage(blackWhiteImage.getFrame());
                        } 
                        if (algSkinFace == true && algFrontFace == false && algProfilFace == false) {
                            p.setImage(blackWhiteImageToBlob.getFrame());
                        }
                        if (algDiff == true && algFrontFace == false && algProfilFace == false && algSkinFace == false) {
                              p.setImage(blackWhiteImageToBlob.getFrame());
                        }
                        p.repaintImage();
                    }


                    if (view == 4) {
                      
                        p.setImage(structBlobs.getImage());
                        p.repaintImage();

                    }
                    
                    if (view == 5) {
                       
                        p.setImage(structBlobs.getImage());
                        p.repaintImage();        
                        p.setLines(thdCount.getP1(), thdCount.getP2());
                    }
                    
                    thdCount.setParameters(squareSize, speedMove);
                    thdCount.setStructure(structBlobs);

                    Thread.sleep(Utils.ftpsToMilisecond(frequence));
                    
                    long detectDuration = System.currentTimeMillis() - detectStartTime;
                    alg_real_fps.setText(Integer.toString(Utils.milisecondToFtps(detectDuration)) + " fps");
                } catch (InterruptedException ex) {
                    Logger.getLogger(InstanceThreadUSB.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    });

    public static void main(String[] args) {
    }
}
